package com.fingard.dsp;

import com.fingard.constant.Format;
import com.fingard.crypto.SignEncryptHelper;
import com.fingard.db.JDBCHelper;
import com.fingard.dsp.bank.reqrespobj.ReqRespHeader;
import com.fingard.dsp.bizbasic.BizObject;
import com.fingard.dsp.tcpserver.BankResetEvent;
import com.fingard.io.FileHelper;
import com.fingard.net.*;
import com.fingard.net.http.BizHttpClient;
import com.fingard.net.listener.HttpReceiver;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.FGBiz;
import org.apache.commons.codec.binary.Base64;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.security.PublicKey;
import java.sql.Connection;
import java.util.*;

/**
 * 前置机转发系统类
 */
public class Transmit implements ITcpClient {
    /**
     * 系统转发配置文件根目录
     */
    public String rootDirPath = "";

    /**
     * 当前转发请求
     */
    public BizObject _bizO = null;

    /**
     * 转发目标主机IP
     */
    public String serverIP = "";
    
    /**http转发目的url*/
    public String destUrl = "";

    /**
     * 转发目标主机服务端口
     */
    public String serverPort = "";

    /**
     * 客户公钥
     */
    public PublicKey publicKey = null;

    /**
     * 转发超时时间(单位：秒，默认120秒)
     */
    public int timeoutSec = 120;
    
    /**字符集*/
    public String charset = "";

    public Transmit(BizObject p_bizO, String p_mainDir) {
        rootDirPath = StringHelper.trimEnd(p_mainDir, File.separator);
        _bizO = p_bizO;
        charset = FGBiz.dspCenter.dspSet.encodingWithDspClient;
    }
    
    /**是否为http转发*/
    public boolean isHttpTransmit = false;
    /**如果是http转发，是否采用BizHttpClient*/
    public boolean useBizHttpClient = false;

    private String proxyIP;
    private int proxyPort;
    private String proxyUser;
    private String proxyPwd;

    private static String queryTransmitsInfo = "select t.custom_no,t.server_ip,t.server_port,t.dest_url,t.protocol,t.cust_cer,t.custom_name,t.bankcode,t.transtype from CORP_TRANSMITS t";
	
    /**设置为http转发的代理*/
	public void setHttpProxy(String pProxyIP,int pProxyPort, String pUser, String pPwd){
		isHttpTransmit = true;
		proxyIP = pProxyIP;
		proxyPort = pProxyPort;
		proxyUser = pUser;
		proxyPwd = pPwd;
	}

    public void setIpAndPort(String ip, String port) {
        serverIP = ip;
        serverPort = port;
    }

    /**
     * 读取前置机转发系统字符集
     *
     * @return
     */
    public String getCharset() {
    	if(StringHelper.hasAnyChar(charset)){
    		return charset;
    	}
    	return FGBiz.dspCenter.dspSet.encodingWithDspClient;
    }

    /**
     * 取转发的目标主机地址，排除转发融汇前置机--DSP监控用
     */
    public ArrayList<String[]> getTransmitIpPortList() throws Exception {
        ArrayList<String[]> retList = new ArrayList<String[]>();
        HashMap<String, String> existIpList = new HashMap<String, String>();

        File tmpFile = new File(rootDirPath + File.separator + "config" + File.separator + "Transmit.xml");
        if (tmpFile.exists()) {
            String strConfig = FileHelper.readToString(tmpFile, "utf-8");
            XmlTextReader xmlReader = new XmlTextReader(strConfig);
            while (xmlReader.read("/config/item")) {
                boolean enable = xmlReader.readedXElement.getAttrValueAsBool("enable");
                if (enable) {
                    String bankCode = xmlReader.readedXElement.getSingleText("bankCode");
                    if (bankCode != null && !bankCode.startsWith("FnGrd")) {
                        String ip = xmlReader.readedXElement.getSingleText("serverIP");
                        String port = xmlReader.readedXElement.getSingleText("serverPort");
                        
                		String destUrl = xmlReader.readedXElement.getSingleText("destUrl");
                        String eachProtocol = xmlReader.readedXElement.getSingleText("protocol");
                        
                        String eachCharset = xmlReader.readedXElement.getSingleText("charset");
                        if(StringHelper.hasAnyChar(eachCharset)){
                        	this.charset = eachCharset;
                        }
                        
                        //非http或destUrl为空，否则是发ats的
                        if(!"http".equalsIgnoreCase(eachProtocol) || StringHelper.isNullOrEmpty(destUrl)){
                        	String chkKey = ip + ":" + port;
                            if (!existIpList.containsKey(chkKey)) {
                                existIpList.put(chkKey, chkKey);
                                retList.add(new String[]{ip, port});
                            }
                        }
                    }
                }
            }
        }
        return retList;
    }

    /**是否为http页面分发*/
    private boolean isHttpPageDistribute = false;
    public String hostRawString = "";
    public String refererRawString = "";
    /**判断是否为http分发
     * @throws Exception */
    public boolean isHttpDistribute(String pPage) throws Exception{
    	File tmpFile = new File(rootDirPath + File.separator + "config" + File.separator + "Transmit.xml");
        if (tmpFile.exists()) {
            String strConfig = FileHelper.readToString(tmpFile, "utf-8");
            XmlTextReader xmlReader = new XmlTextReader(strConfig);
            while (xmlReader.read("/config/item")) {
                boolean enable = xmlReader.readedXElement.getAttrValueAsBool("enable");
                if (enable) {
                	String page = xmlReader.readedXElement.getSingleTextNotNull("page").trim().toLowerCase();
                	String eachProtocol = xmlReader.readedXElement.getSingleText("protocol");
                    if("httpDistribute".equalsIgnoreCase(eachProtocol)){
                    	if(pPage.toLowerCase().startsWith(page)){
	                    	this.isHttpPageDistribute = true;
	                    	serverIP = xmlReader.readedXElement.getSingleText("serverIP");
	                        serverPort = xmlReader.readedXElement.getSingleText("serverPort");
	                        destUrl = xmlReader.readedXElement.getSingleText("destUrl");
	                        String eachCharset = xmlReader.readedXElement.getSingleText("charset");
	                        if(StringHelper.hasAnyChar(eachCharset)){
	                        	this.charset = eachCharset;
	                        }
	                        String timeout = xmlReader.readedXElement.getSingleText("timeoutSec");
	                        if (StringHelper.hasAnyChar(timeout)) {
	                            timeoutSec = Integer.parseInt(timeout);
	                        }else{
	                        	timeoutSec = 5;
	                        }
	                    	return true;
                    	}
                    }
                }
            }
        }
        return false;
    }
    
    
    /**
     * 当前系统请求是否需要进行转发判断
     *
     * @param p_header
     * @return
     * @throws Exception
     */
    public boolean isTransmit(ReqRespHeader p_header) throws Exception {
        if ("GetBankFrontStatus".equals(p_header.transType)) {
            return false;
        }

        File tmpFile = new File(rootDirPath + File.separator + "config" + File.separator + "Transmit.xml");
        if (tmpFile.exists()) {
            String strConfig = FileHelper.readToString(tmpFile, "utf-8");
            XmlTextReader xmlReader = new XmlTextReader(strConfig);

            if(xmlReader.read("/config/httpProxy")){
                if(xmlReader.readedXElement.getAttrValueAsBool("enable"))
                {
                    this.proxyIP = xmlReader.readedXElement.getSingleText("ip");
                    String sPort =  xmlReader.readedXElement.getSingleText("port");
                    if(StringHelper.hasAnyChar(sPort)){
                        this.proxyPort = Integer.parseInt(sPort);
                    }
                    this.proxyUser =  xmlReader.readedXElement.getSingleText("user");
                    this.proxyPwd = xmlReader.readedXElement.getSingleText("pwd");
                }
            }
            xmlReader.backToTop();
            //是否从数据库获取相关配置
            String useDBConn = xmlReader.getFirstText("/config/useDBConn");
            if("true".equals(useDBConn)){
                Connection dbConn = null;
                try {
                    dbConn = com.fingard.FGBiz.dspCenter.dspSet.dbConnectionSet.getConnection();
                    List<Map<String, Object>> transmitsInfoList = JDBCHelper.execQuery(dbConn, queryTransmitsInfo,new Object[]{});
                    for(Map<String, Object> transmitsInfo : transmitsInfoList){
                        String transType = StringHelper.valueOf(transmitsInfo.get("TRANSTYPE"));
                        String bankCode = StringHelper.valueOf(transmitsInfo.get("BANKCODE"));
                        String systemCode = "";
                        String entity = "";
                        String tenant = StringHelper.valueOf(transmitsInfo.get("CUSTOM_NO"));

                        boolean isMatch = isMatch(p_header, transType, bankCode, systemCode, entity, tenant);

                        if (isMatch) {
                            serverIP = StringHelper.valueOf(transmitsInfo.get("SERVER_IP"));
                            serverPort = StringHelper.valueOf(transmitsInfo.get("SERVER_PORT"));
                            destUrl = StringHelper.valueOf(transmitsInfo.get("DEST_URL"));
                            String custCer = StringHelper.valueOf(transmitsInfo.get("CUST_CER"));
                            if(StringHelper.hasAnyChar(custCer)){
                                publicKey = SignEncryptHelper.getPubkeyByBase64Str(custCer);
                            }
                            //判断是否需要http转发，默认socket
                            isHttpTransmit = "http".equalsIgnoreCase(StringHelper.valueOf(transmitsInfo.get("PROTOCOL")))?true:false;
                            timeoutSec = 120;//超时时间，单位：秒
                            return true;
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    if (dbConn != null) {
                        dbConn.close();
                    }
                }
            }else{
                while (xmlReader.read("/config/item")) {
                    boolean enable = xmlReader.readedXElement.getAttrValueAsBool("enable");
                    if (enable) {
                        String transType = xmlReader.readedXElement.getSingleTextNotNull("transType").trim();
                        String bankCode = xmlReader.readedXElement.getSingleTextNotNull("bankCode").trim();
                        String systemCode = xmlReader.readedXElement.getSingleTextNotNull("systemCode").trim();
                        String entity = xmlReader.readedXElement.getSingleTextNotNull("entity").trim();
                        String tenant = xmlReader.readedXElement.getSingleTextNotNull("tenant").trim();

                        boolean isMatch = isMatch(p_header, transType, bankCode, systemCode, entity, tenant);

                        if (isMatch) {
                            serverIP = xmlReader.readedXElement.getSingleText("serverIP");
                            serverPort = xmlReader.readedXElement.getSingleText("serverPort");
                            destUrl = xmlReader.readedXElement.getSingleText("destUrl");
                            String custCer = xmlReader.readedXElement.getSingleText("custCer");
                            if(StringHelper.hasAnyChar(custCer)){
                                publicKey = SignEncryptHelper.getPubkeyByBase64Str(custCer);
                            }
                            String eachCharset = xmlReader.readedXElement.getSingleText("charset");
                            if(StringHelper.hasAnyChar(eachCharset)){
                            	this.charset = eachCharset;
                            }
                            String eachProtocol = xmlReader.readedXElement.getSingleText("protocol");
                            if("http".equalsIgnoreCase(eachProtocol)){
                            	this.isHttpTransmit = true;
                            }
                            //BizHttpClient
                            String useBizClient = xmlReader.readedXElement.getSingleTextNotNull("useBizClient");
                            if("true".equalsIgnoreCase(useBizClient)){
                            	useBizHttpClient = true;
                            }
                            String timeout = xmlReader.readedXElement.getSingleText("timeoutSec");
                            if (StringHelper.hasAnyChar(timeout)) {
                                timeoutSec = Integer.parseInt(timeout);
                            }
                            return true;
                        }
                    }
                }
            }
        }


        return false;
    }

    private boolean isMatch(ReqRespHeader p_header, String transType, String bankCode, String systemCode, String entity, String tenant) {
        boolean isMatch = !(StringHelper.isNullOrEmpty(tenant) && StringHelper.isNullOrEmpty(entity) && StringHelper.isNullOrEmpty(systemCode) && StringHelper.isNullOrEmpty(bankCode) && StringHelper.isNullOrEmpty(transType));
        if (isMatch) {
            if (StringHelper.isNullOrEmpty(tenant) || tenant.equals("*") || tenant.equals(p_header.tenant)) {
                isMatch = true;
            } else {
                tenant = "," + tenant.replace(" ", "").replace("\t", "") + ",";
                if (tenant.contains("," + p_header.tenant + ",")) {
                    isMatch = true;
                } else {
                    isMatch = false;
                }
            }
        }

        if (isMatch) {
            if (StringHelper.isNullOrEmpty(entity) || entity.equals("*") || entity.equals(p_header.corporation)) {
                isMatch = true;
            } else {
                entity = "," + entity.replace(" ", "").replace("\t", "") + ",";
                if (entity.contains("," + p_header.corporation + ",")) {
                    isMatch = true;
                } else {
                    isMatch = false;
                }
            }
        }

        if (isMatch) {
            if (StringHelper.isNullOrEmpty(systemCode) || systemCode.equals("*") || systemCode.equals(p_header.group)) {
                isMatch = true;
            } else {
                systemCode = "," + systemCode.replace(" ", "").replace("\t", "") + ",";
                if (systemCode.contains("," + p_header.group + ",")) {
                    isMatch = true;
                } else {
                    isMatch = false;
                }
            }
        }

        if (isMatch) {
            if (StringHelper.isNullOrEmpty(bankCode) || bankCode.equals("*") || bankCode.equals(p_header.bankCode)) {
                isMatch = true;
            } else {
                bankCode = "," + bankCode.replace(" ", "").replace("\t", "") + ",";
                if (p_header.bankCode != null && bankCode.contains("," + p_header.bankCode + ",")) {
                    isMatch = true;
                } else {
                    isMatch = false;
                }
            }
        }

        if (isMatch) {
            if (StringHelper.isNullOrEmpty(transType) || transType.equals("*") || transType.equals(p_header.transType)) {
                isMatch = true;
            } else {
                transType = "," + transType.replace(" ", "").replace("\t", "") + ",";
                if (transType.contains("," + p_header.transType + ",")) {
                    isMatch = true;
                } else {
                    isMatch = false;
                }
            }
        }
        return isMatch;
    }

    /**
     * 目标前置机转发执行器
     *
     * @param pReqBytes
     * @return
     * @throws Exception
     */
    public String doTransmit(byte[] pReqBytes) throws Exception {
        if(isHttpTransmit){
        	return doTransmitHttp(pReqBytes);
        }else{
        	return doTransmitSocket(pReqBytes);
        }
    }
    
    
    private void doHttpDispatch(SocketChannel pSrcSocketChannel, SocketChannel pDestSocketChannel, int pDistributeType){

    	try {
    		boolean isContinue = true;
    		int countZeroRead = 0;
    		while(isContinue){
    			byte[] readBytes = new byte[20480];//20K
    			ByteBuffer readBuffer = ByteBuffer.wrap(readBytes);
    			if(pDistributeType==2){
    				//System.out.println("1 type:"+pDistributeType+", src.SoTimeout:"+pSrcSocketChannel.socket().getSoTimeout());
    			}
    			//从来源读
    			int readLen = pSrcSocketChannel.read(readBuffer);
    			if(pDistributeType==1){
    				//System.out.println("从来源读取：readLen:"+readLen);
    			}else if(pDistributeType==2){
    				//System.out.println("从目的读取：readLen:"+readLen);
    			}
    			
    			if(readLen>0){
    				countZeroRead = 0;
    				//System.out.println("请求：\r\n"+reqStr+"\r\n-----------\r\n");
    				//发目的
    				ByteBuffer writeBuffer = null;
    				if(pDistributeType == 1){
    					String reqStr = new String(readBytes, 0, readLen, charset);
    					if(reqStr.contains(hostRawString)){	
    						reqStr = reqStr.replace(hostRawString, "Host: "+this.serverIP+":"+this.serverPort);
    						reqStr = reqStr.replace(IpHelper.getLocalHostIp()+":"+FGBiz.dspCenter.dspSet.listenerPort, serverIP+":"+serverPort);
    						readBytes = reqStr.getBytes(charset);
    						writeBuffer = ByteBuffer.wrap(readBytes);
    					}
    				}
    				if(writeBuffer == null){
    					writeBuffer = readBuffer;
    				}
    				writeBuffer.position(0);
    				pDestSocketChannel.write(writeBuffer);
    				if(pDistributeType == 2){
    					//System.out.println("type:"+pDistributeType+", set()1");
    					this.resetEvent1.set();
    				}else{
    					//System.out.println("type:"+pDistributeType+", set()2");
    					resetEvent2.set();
    				}
    			}else{
    				countZeroRead++;
    				
    				if((pDistributeType == 1 && countZeroRead>=10) || (pDistributeType == 2 && countZeroRead>=2)){
    					//System.out.println("type:"+pDistributeType+", stop");
    					try {
    						pSrcSocketChannel.close();
    					} catch (IOException ex1) {
    						
    					}
    					break;
    				}
    				
    				 if(pDistributeType == 1){
    					 //System.out.println("type:"+pDistributeType+", waitOne()1");
    					 if(countZeroRead>5){
    						 resetEvent1.setTimeout(800);
    					 }
    					 this.resetEvent1.waitOne();
    				 }else{
    					 //System.out.println("type:"+pDistributeType+", waitOne()2");
    					 this.resetEvent2.waitOne();
    				 }
    			}
    		}
		}catch (IOException e) {
			//System.out.println("type:"+pDistributeType+", "+LogHelper.getStackTraceFirstLine(e));
				try {
					pSrcSocketChannel.close();
				} catch (IOException e1) {
					
				}	
			
		} catch (Exception e) {
			FGBiz.limitMsg.exception("HttpDispatcher", e);
			try {
				pSrcSocketChannel.close();
			} catch (IOException e1) {
				
			}
		}
    }
    
    private BankResetEvent resetEvent1;
    private BankResetEvent resetEvent2;
    private SocketChannel destSocketChannel;
    public void initHttpDistribute() throws IOException{
    	destSocketChannel = SocketChannel.open();
    	destSocketChannel.configureBlocking(true);
    	destSocketChannel.connect(new InetSocketAddress(serverIP, Integer.parseInt(serverPort)));
    	destSocketChannel.socket().setSoTimeout(timeoutSec * 1000);
    	
    	resetEvent1 = new BankResetEvent(500);
    	resetEvent2 = new BankResetEvent(500);
    }
    private volatile boolean isHttpDistributeClosed = false;
    public void closeHttpDistribute(){
    	if(!isHttpDistributeClosed){
    		isHttpDistributeClosed = true;
	    	if(destSocketChannel != null){
	    		try {
					destSocketChannel.close();
					destSocketChannel = null;
				} catch (IOException e) {
					FGBiz.limitMsg.exception("Transmit.closeHttpDistribute", e);
				}
	    	}
    	}
    	if(resetEvent1!=null){
    		resetEvent1=null;
    	}
    	if(resetEvent2!=null){
    		resetEvent2=null;
    	}
    }
    
    public void doHttpDistribute(String pReqStr, int pDistributeType) throws Exception{
    	//System.out.println("DistributeType:"+pDistributeType);
    	SocketChannel srcSocketChannel = _bizO.reqSocketReceiver.clientSocketChannel;
    	if(pDistributeType == 1){
    		pReqStr = pReqStr.replace(this.hostRawString, "Host: "+this.serverIP+":"+this.serverPort);
        	//_bizO.sbLog.append("http分发至 " + serverIP + ":" + serverPort + "，超时时间：" + this.timeoutSec + "秒；\r\n\r\n");
        	//System.out.println("请求：\r\n"+pReqStr);
        	byte[] bytesToDest = pReqStr.getBytes(getCharset());
        	//发送目的服务器
    		destSocketChannel.write(ByteBuffer.wrap(bytesToDest));
    		srcSocketChannel.socket().setSoTimeout(timeoutSec*1000);
    		doHttpDispatch(srcSocketChannel, destSocketChannel, pDistributeType);
    	}else if(pDistributeType == 2){
    		doHttpDispatch(destSocketChannel, srcSocketChannel, pDistributeType);
    	}
    }
    
    public String[] getAESKeyHttp(byte[] pReqBytes) throws Exception {
    	String url="";
    	if(StringHelper.hasAnyChar(destUrl)){
    		url = destUrl+"/encrypt";
    	}else{
    		url = "http://"+serverIP+":"+serverPort+"/dsp/encrypt";
    	}
    	_bizO.sbLog.append("采用http转发至 " + url + "，超时时间：" + this.timeoutSec + "秒\r\n");
    	if(StringHelper.hasAnyChar(this.proxyIP)){
    		_bizO.sbLog.append("代理服务器："+this.proxyIP+"\r\n");
    	}
    	if(useBizHttpClient) {
    	    String[] retStr = new String[]{"",""};
            BizHttpClient bizClient = new BizHttpClient(url, this.getCharset());
            HttpReceiver bizReceiver = bizClient.post(pReqBytes);
            if (!bizReceiver.isCompleted && StringHelper.hasAnyChar(bizReceiver.connState)) {
                return new String[]{"",StringHelper.joinNotEmpty(bizReceiver.connState, bizReceiver.connMsg)};
            } else {

                String resp =bizReceiver.getContentString(this.getCharset());
                if (resp.length() > 6) {
                    _bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + _bizO.seqIDInner + " 对称密钥响应报文\r\n" + resp + "\r\n");

                    String respCode = resp.substring(0, 6);
                    retStr[0] = respCode;
                    if ("000000".equals(respCode)) {
                        byte[] decrypt = Base64.decodeBase64(resp.substring(6).getBytes());
                        retStr[1] = SignEncryptHelper.doDecryptByRSA2(decrypt, FGBiz.dspCenter.dspSet.certConfig.ownPriKey);
                        _bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + _bizO.seqIDInner + " 密钥请求响应明文：\r\n" + retStr[1] + "\r\n");
                    } else {
                        retStr[1] = resp.substring(6);
                    }
                } else {
                    _bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + _bizO.seqIDInner + " 对称密钥响应报文\r\n" + resp + "\r\n");
                }
                return retStr;
            }
        }else {
            WebRequest webReq = new WebRequest(url, proxyIP, proxyPort, proxyUser, proxyPwd);
            webReq.setHttpTransmit();
            webReq.setSbLog(_bizO.sbLog);
            webReq.setRequestProperty("Content-Type", "application/xml");
            webReq.setReadTimeout(timeoutSec * 1000);

            byte[] tmpWriteBytes = pReqBytes;
            String[] retStr = webReq.upload(tmpWriteBytes, getCharset());
            if (StringHelper.isNullOrEmpty(retStr[0]) && retStr[1].length() > 6) {
                _bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + _bizO.seqIDInner + " 对称密钥响应报文\r\n" + retStr[1] + "\r\n");

                String respCode = retStr[1].substring(0, 6);
                retStr[0] = respCode;
                if ("000000".equals(respCode)) {
                    byte[] decrypt = Base64.decodeBase64(retStr[1].substring(6).getBytes());
                    retStr[1] = SignEncryptHelper.doDecryptByRSA2(decrypt, FGBiz.dspCenter.dspSet.certConfig.ownPriKey);
                    _bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + _bizO.seqIDInner + " 密钥请求响应明文：\r\n" + retStr[1] + "\r\n");
                } else {
                    retStr[1] = retStr[1].substring(6);
                }
            } else {
                _bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + _bizO.seqIDInner + " 对称密钥响应报文\r\n" + retStr[0] + "\r\n" + retStr[1] + "\r\n");
            }
            return retStr;
        }
    }


    private String doTransmitHttp(byte[] pReqBytes) throws Exception {
        String url="";
        if(StringHelper.hasAnyChar(destUrl)){
            url = destUrl;
        }else{
            url = "http://"+serverIP+":"+serverPort+"/dsp";
        }
        _bizO.sbLog.append("采用http转发至 " + url + "，超时时间：" + this.timeoutSec + "秒\r\n");
        if(StringHelper.hasAnyChar(this.proxyIP)){
            _bizO.sbLog.append("代理服务器："+this.proxyIP+"\r\n");
        }

        if(useBizHttpClient){
        	BizHttpClient bizClient = new BizHttpClient(url, this.getCharset());
            if(FGBiz.dspCenter.dspSet.enableEncrypt&&publicKey!=null){
                bizClient.setReqProperty("content-sign","true");
                if(destUrl.startsWith("https:")){
                    bizClient.setReqProperty("content-encrypt","false");
                }else {
                    bizClient.setReqProperty("content-encrypt","true");
                }
            }else{
                bizClient.setReqProperty("content-sign","false");
                bizClient.setReqProperty("content-encrypt","false");
            }
        	HttpReceiver bizReceiver = bizClient.post(pReqBytes);
        	if(!bizReceiver.isCompleted && StringHelper.hasAnyChar(bizReceiver.connState)){
        		return StringHelper.joinNotEmpty(bizReceiver.connState, bizReceiver.connMsg);
        	}else{
        		return bizReceiver.getContentString(this.getCharset());
        	}
        }else{
        	WebRequest webReq = new WebRequest(url, proxyIP, proxyPort, proxyUser, proxyPwd);
            webReq.setHttpTransmit();
            webReq.setSbLog(_bizO.sbLog);
            webReq.setRequestProperty("Content-Type","application/xml");
            if(FGBiz.dspCenter.dspSet.enableEncrypt&&publicKey!=null){
                webReq.setRequestProperty("content-sign","true");
                if(destUrl.startsWith("https:")){
                    webReq.setRequestProperty("content-encrypt","false");
                }else {
                    webReq.setRequestProperty("content-encrypt","true");
                }
            }else{
                webReq.setRequestProperty("content-sign","false");
                webReq.setRequestProperty("content-encrypt","false");
            }

            webReq.setReadTimeout(timeoutSec*1000);

            byte[] tmpWriteBytes = pReqBytes;

            String[] retStr = webReq.upload(tmpWriteBytes, getCharset());
            return retStr[1];
        }
    }
    
    private String doTransmitSocket(byte[] pReqBytes) throws Exception {
    	_bizO.sbLog.append("转发至 " + serverIP + ":" + serverPort + "，超时时间：" + this.timeoutSec + "秒；\r\n\r\n");
        TcpPortClient tmpClient = new TcpPortClient(serverIP, Integer.parseInt(serverPort), this);
        tmpClient.timeoutMil = this.timeoutSec * 1000;

        byte[] tmpBytesBody = pReqBytes;
        String tmpSendHead = "Content-Length:" + String.format("% 8d", tmpBytesBody.length) + "\r\n";
        byte[] tmpBytesHead = tmpSendHead.getBytes(getCharset());

        byte[] tmpBytesSend = new byte[tmpBytesHead.length + tmpBytesBody.length];
        System.arraycopy(tmpBytesHead, 0, tmpBytesSend, 0, tmpBytesHead.length);
        System.arraycopy(tmpBytesBody, 0, tmpBytesSend, tmpBytesHead.length, tmpBytesBody.length);

        TcpReceiver tmpReceiver = tmpClient.sendMessage(tmpBytesSend);
        if (tmpReceiver.isCompleted) {
        	if(this.isHttpPageDistribute){
        		return tmpReceiver.getFullString(getCharset());
        	}else{
        		return new String(tmpReceiver.recBytes, tmpReceiver.contentStartIndex, tmpReceiver.contentLength, getCharset());
        	}
        } else {
            if (tmpReceiver.connState == ConnState.FAIL) {
            	String reqStr = new String(pReqBytes, getCharset());
                XmlTextReader tmpBkReader = new XmlTextReader(reqStr);
                if (tmpBkReader != null) {
                    String transType = tmpBkReader.getFirstText("/ATSYH/TransReq/TransType");
                    String bankCode = tmpBkReader.getFirstText("/ATSYH/TransReq/BankCode");
                    String transSeqID = tmpBkReader.getFirstText("/ATSYH/TransReq/TransSeqID");
                    if ("1908".equals(transType)) {
                        String returnStr = "<ATSYH><TransResp><BankCode>%s</BankCode><TransType>1908</TransType><TransSeqID>%s</TransSeqID><TransParam><DetailRecord><RespCode>0</RespCode><RespInfo>连接失败！</RespInfo><TransState>ConnectionRefused</TransState><ReqSeqID>%s</ReqSeqID><PayInfoCode>ConnectionRefused</PayInfoCode></DetailRecord></TransParam></TransResp></ATSYH>";
                        String reqSeqID = tmpBkReader.getFirstText("/ATSYH/TransReq/TransParam/DetailRecord/ReqSeqID");
                        return String.format(returnStr, bankCode, transSeqID, reqSeqID);
                    }
                }
            }
            return tmpReceiver.getConnMsg();
        }
    }
    
    /*
    private HashMap<String,String> getHttpHead(byte[] pRecBytes){
    	for (int i = 0; i < pRecBytes.length; i++) {
        	if (pRecBytes[i] == tmpHeadCut2){// 是\n
                int tmpEndCount = i - readHeadStartIndex;
                if (i > 1 && p_receiver.recBytes[i - 1] == tmpHeadCut1){// 前一个字符是\r
                	tmpEndCount--;
                }
                String tmpHeadKeyValue = new String(p_receiver.recBytes, readHeadStartIndex, tmpEndCount, this.getCharset());
                String tmpKey = "";
                String tmpValue = "";
                
                int idx1 = tmpHeadKeyValue.indexOf(":");
                if(idx1>0){
                	tmpKey = tmpHeadKeyValue.substring(0,idx1).toLowerCase().trim();
					if(!"filepath".equals(tmpKey)) {
						tmpValue = tmpHeadKeyValue.substring(idx1 + 1).toLowerCase();
					}else{
						tmpValue = tmpHeadKeyValue.substring(idx1 + 1);
					}
                }else{
                	tmpKey = tmpHeadKeyValue.toLowerCase().trim();
                }
                p_receiver.headKV.put(tmpKey, tmpValue.trim());

                if (tmpKey.equals("host")){
                	p_receiver.hostRawString = tmpHeadKeyValue;
                }
                
                if (tmpKey.equals("content-length")){
                	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                }else if (tmpKey.equals("cipher-length")){
                	p_receiver.isCipherSocket = true;
                	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                }else if (tmpKey.equals("tenant-connect")){
                	p_receiver.isTenantRemoting = true;
                	p_receiver.isCipherSocket = true;
                	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                }else if (tmpKey.equals("syncfile-length")){
                	p_receiver.isSyncFile = true;
                	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                	p_receiver.action = "syncfile";
                	tmpHeader.transType = "syncfile";
                }else if (tmpKey.equals("action")){
                	action = tmpValue;
                }else if (tmpKey.equals("append")){
                	if("true".equals(tmpValue)){
                		appendFile = true;
                	}
                }else if (tmpKey.equals("bankcode")){
                	tmpHeader.bankCode = tmpValue;
                }else if (tmpKey.equals("sybank")){
                	tmpHeader.syBank = tmpValue;
                }else if (tmpKey.equals("filepath")){
                	oriFilePath = tmpValue.replace("\\", File.separator).replace("/", File.separator);
                }else if (tmpKey.equals("filetype")){
                	fileType = tmpValue;
                }else if (tmpKey.equals("charset")){
                	charsetName = tmpValue;
                }else if (tmpKey.equals("cipher-key")){
                	cipherKey = tmpValue;
                }else if (tmpKey.equals("cipher-iv")){
                	cipherIV = tmpValue;
                }else if (tmpKey.equals("digest-sign")){
                	digestSign = tmpValue;
                }
                readHeadStartIndex = i + 1;
                if (p_receiver.receiveOffSet > (i + 2)){
                    if (p_receiver.recBytes[i + 1] == tmpHeadCut1 && p_receiver.recBytes[i + 2] == tmpHeadCut2){
                    	p_receiver.contentStartIndex = i + 3;
                        break;
                    }
                }
            }else if (p_receiver.recBytes[i] == tmpByteLt){// 是<
            	p_receiver.contentStartIndex = i;
                break;
            }
        }
    }*/

    private static byte tmpByteLt = '<';//"<".getBytes("gbk")[0];
    private static byte tmpHeadCut1 = '\r';//"\\r".getBytes("gbk")[0];
    private static byte tmpHeadCut2 = '\n';//"\\n".getBytes("gbk")[0];
    private int readHeadStartIndex = 0;
    
    public void getContentLength(TcpReceiver p_receiver) throws Exception {
        if (p_receiver.contentLength == -1) {
        	if(this.isHttpPageDistribute){
        		//String aaa = p_receiver.getFullString(getCharset());
        		//System.out.println(aaa);
        		for (int i = readHeadStartIndex; i < p_receiver.readedLength; i++) {
                	if (p_receiver.recBytes[i] == tmpHeadCut2){// 是\n
                        int tmpEndCount = i - readHeadStartIndex;
                        if (i > 1 && p_receiver.recBytes[i - 1] == tmpHeadCut1){// 前一个字符是\r
                        	tmpEndCount--;
                        }
                        String tmpHeadKeyValue = new String(p_receiver.recBytes, readHeadStartIndex, tmpEndCount, this.getCharset());
                        String tmpKey = "";
                        String tmpValue = "";
                        
                        int idx1 = tmpHeadKeyValue.indexOf(":");
                        if(idx1>0){
                        	tmpKey = tmpHeadKeyValue.substring(0,idx1).toLowerCase().trim();
    						if(!"filepath".equals(tmpKey)) {
    							tmpValue = tmpHeadKeyValue.substring(idx1 + 1).toLowerCase();
    						}else{
    							tmpValue = tmpHeadKeyValue.substring(idx1 + 1);
    						}
                        }else{
                        	tmpKey = tmpHeadKeyValue.toLowerCase().trim();
                        }
                        p_receiver.headKV.put(tmpKey, tmpValue.trim());

                        if (tmpKey.equals("host")){
                        	p_receiver.hostRawString = tmpHeadKeyValue;
                        }
                        
                        if (tmpKey.equals("content-length")){
                        	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                        }/*else if (tmpKey.equals("cipher-length")){
                        	p_receiver.isCipherSocket = true;
                        	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                        }else if (tmpKey.equals("tenant-connect")){
                        	p_receiver.isTenantRemoting = true;
                        	p_receiver.isCipherSocket = true;
                        	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                        }else if (tmpKey.equals("syncfile-length")){
                        	p_receiver.isSyncFile = true;
                        	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                        	p_receiver.action = "syncfile";
                        	tmpHeader.transType = "syncfile";
                        }else if (tmpKey.equals("action")){
                        	action = tmpValue;
                        }else if (tmpKey.equals("append")){
                        	if("true".equals(tmpValue)){
                        		appendFile = true;
                        	}
                        }else if (tmpKey.equals("bankcode")){
                        	tmpHeader.bankCode = tmpValue;
                        }else if (tmpKey.equals("sybank")){
                        	tmpHeader.syBank = tmpValue;
                        }else if (tmpKey.equals("filepath")){
                        	oriFilePath = tmpValue.replace("\\", File.separator).replace("/", File.separator);
                        }else if (tmpKey.equals("filetype")){
                        	fileType = tmpValue;
                        }else if (tmpKey.equals("charset")){
                        	charsetName = tmpValue;
                        }else if (tmpKey.equals("cipher-key")){
                        	cipherKey = tmpValue;
                        }else if (tmpKey.equals("cipher-iv")){
                        	cipherIV = tmpValue;
                        }else if (tmpKey.equals("digest-sign")){
                        	digestSign = tmpValue;
                        }*/
                        readHeadStartIndex = i + 1;
                        if (p_receiver.receiveOffSet > (i + 2)){
                            if (p_receiver.recBytes[i + 1] == tmpHeadCut1 && p_receiver.recBytes[i + 2] == tmpHeadCut2){
                            	p_receiver.contentStartIndex = i + 3;
                                break;
                            }
                        }
                    }else if (p_receiver.recBytes[i] == tmpByteLt){// 是<
                    	p_receiver.contentStartIndex = i;
                        break;
                    }
                }
        	}else{
        		for (int i = 0; i < p_receiver.readedLength; i++) {
                    if (p_receiver.recBytes[i] == "<".getBytes(getCharset())[0]) {
                        p_receiver.contentStartIndex = i;
                        String[] tmpKeyValues = new String(p_receiver.recBytes, 0, i, getCharset()).split("\n");
                        for (int j = 0; j < tmpKeyValues.length; j++) {
                            String[] tmpEach = tmpKeyValues[j].split(":");
                            if (tmpEach[0].toLowerCase().equals("content-length")) {
                                p_receiver.contentLength = Integer.valueOf(tmpEach[1].trim());
                            }
                        }
                        break;
                    }
                }
        	}
        }
    }

    public static void main(String[] args) throws Exception{


        URL url = new URL("http://127.0.0.1:6060/dsp/encrypt");
        HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
        httpConnection.setConnectTimeout(120*1000);
        byte[] p_upBytes = "<ATSYH version=\"5.1.0.0\"><TransReq><Tenant>1352</Tenant><BankCode>BOC01</BankCode><SystemCode>Default</SystemCode><TransType>7506</TransType><TransSeqID>1348166660</TransSeqID><TransTime>2020-01-02 13:48:16</TransTime><TransParam></TransParam></TransReq></ATSYH>".getBytes("gbk");

        String[] retStr = new String[]{"",""};
        String connCode = "";
        if(connCode.length() == 0){
            OutputStream outputStream = null;
            InputStream inputStream = null;
            try {
                httpConnection.setDoInput(true);// 从服务器获取数据

                httpConnection.setUseCaches(false);
                if(p_upBytes != null){
                    httpConnection.setDoOutput(true);// 向服务器写入数据
                    httpConnection.setRequestMethod("POST");
                    httpConnection.setRequestProperty("Content-Length", String.valueOf(p_upBytes.length));
                    outputStream = (OutputStream) httpConnection.getOutputStream();
                }
                else{
                    httpConnection.setRequestMethod("GET");
                }
            }
            catch (IOException e) {

            }
            if(retStr[0].length() == 0){
                try{
                    if(p_upBytes != null){
                        outputStream.write(p_upBytes);
                        outputStream.flush();

                    }
                    inputStream = (InputStream) httpConnection.getInputStream();
                    retStr[1] = changeInputStream(inputStream, "gbk");

                    inputStream.close();
                }
                catch (IOException e) {
                    retStr[1] = e.toString();//LogHelper.getStackTrace(e);//e.getMessage();
                }
            }
            try {
                if(inputStream != null){
                    inputStream.close();
                }
            }
            catch (IOException e) {
            }
            try {
                if(outputStream != null){
                    outputStream.close();
                }
            }
            catch (IOException e) {
            }
            httpConnection.disconnect();
        }
        else{
//            retStr[1] = connMsg;
        }
        System.out.println(retStr[1]);
    }
    public static String changeInputStream(InputStream inputStream, String encode) throws IOException{
        // ByteArrayOutputStream 一般叫做内存流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        int len = 0;
        String result = "";
        if (inputStream != null) {
            while ((len = inputStream.read(data)) != -1) {
                byteArrayOutputStream.write(data, 0, len);
            }
            result = new String(byteArrayOutputStream.toByteArray(), encode);
            byteArrayOutputStream.close();
        }

        return result;
    }
}